//	--------------------------------------------------------------------
//	Copyright(C) 2006,2007 Zhao Yukun. All rights reserved.
//	This file is a part of the Xeres system.
//	Xeres 2007
//	Contact : xeres.engine@gmail.com
//	$(reservedInfo)
//	$(reservedDeclaration)
//	--------------------------------------------------------------------
///	@file	<thread_debug.h>
///	@path	~/src/lib/system/
///	@date	2007/11/10
///	@desc	Thread debugging.

#pragma once

#include "xeres.h"

#include "lib/utilities/debug.h"
#include "lib/utilities/string.h"

namespace xeres {

	// check current thread safe (only with this thread)

#if (XERES_DEBUG_ENABLE_THREAD_SAFE_CHECK)
#	define	THREAD_SAFE_CHECK()		\
	static HANDLE s_thread_safe = NULL; \
	if( s_thread_safe == NULL ) s_thread_safe = ::GetCurrentThread();\
	else assert( s_thread_safe == ::GetCurrentThread();
#else
#	define	THREAD_SAFE_CHECK()
#endif // XERES_DEBUG_ENABLE_THREAD_SAFE_CHECK
	
	/*!
		\brief	Function body for macro \ref DEFINE_THREAD_CHECK.
	*/
	void thread_check_define( const wchar_t * cat );

	/*!
		\brief	Function body for macro \ref THREAD_CHECK_AFFECT.
	*/
	void thread_check_affect( const wchar_t * cat , bool affected );

	/*! 
		\struct	rule_cache
		\brief	Structure for rule caching.
	*/
	struct rule_cache
	{
		void * rule;

		// ctor
		rule_cache( const wchar_t * rules );

		// check
		bool check( const wchar_t * function );
	};

	/*!
		\brief	Function body for macro \ref RUNNING_ON_THREAD.
	*/
//	bool thread_check_by_rule( const wchar_t * rules , const wchar_t * function );

	/*! 
		\def	DEFINE_THREAD_CHECK( CAT )
		\details
			Many operations need to run on qualified threads or must not run on specific threads.
			We can define a category for a thread or a thread pool with threads,
			then check operation by matching current thread's category with rules.
			Like we don't want some routines run on background threads(e.g. it might cause synchronize problem),
			a category like 'workers*' can be defined, and make background threads to join it.
			A check will be perform at the beginning of the routine, to check if current thread is in
			'workers*' category, to pervent illegal execution.

		\sa	THREAD_CHECK_AFFECT, RUNNING_ON_THREAD
	*/

	/*! 
		\def	THREAD_CHECK_AFFECT( CAT , AFFECTED )
		\details
			Pause a category's effect on current thread, for intrusive execution,
			a special hack for Xeres engine core's parallelize execution.
			Should not be used else where.

		\sa	DEFINE_THREAD_CHECK, RUNNING_ON_THREAD
	*/

	/*! 
		\def	RUNNING_ON_THREAD( RULES )
		\details
			Check if current thread's category matches the rule.<BR>
			A rule can be a serial of sub expressions combined with '|'.
			Expressions can refer to any category & can with a '!' prefix to
			indicate the following category is not expected.<BR>
			If we want to check if the next operation runs on <tt>'main'</tt> and not runs on <tt>'worker*'</tt>,
			a rule should be <tt>(main|!worker*)</tt>.

		\sa	DEFINE_THREAD_CHECK, THREAD_CHECK_AFFECT
	*/

#if (XERES_DEBUG_ENABLE_THREAD_SAFE_CHECK) && (!defined _PYXERES)

#	define	DEFINE_THREAD_CHECK( CAT ) \
	( xeres::thread_check_define( CAT ) )

#	define	THREAD_CHECK_AFFECT( CAT , AFFECTED ) \
	( xeres::thread_check_affect( CAT , AFFECTED ) )

#	define	RUNNING_ON_THREAD( RULES )	\
	{ \
		static xeres::rule_cache s_threadCheckRules( RULES ); \
		if( !s_threadCheckRules.check( __FUNCTIONW__ ) ) \
			assert( ! #RULES );\
	}

	/// \brief	Reset all thread definition.
	void thread_check_reset_all( void );

#else

#	define	DEFINE_THREAD_CHECK( CAT )

#	define	THREAD_CHECK_AFFECT( CAT , AFFECTED )

#	define	RUNNING_ON_THREAD( RULES )

	static void thread_check_reset_all( void ) {}

#endif // XERES_DEBUG_ENABLE_THREAD_SAFE_CHECK


} // namespace xeres
